Skip to content

Complete Kernel-managed Visa card checkout in CLI - #283

Merged
hiroTamada merged 5 commits into
mainfrom
hypeship/kernel-vault-wallet-card
Oct 13, 2026
Merged

hiroTamada merged 5 commits into
mainfrom
hypeship/kernel-vault-wallet-card

Conversation

@hiroTamada

@hiroTamada hiroTamada commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

summary

  • support Kernel-managed wallet enrollment and card purchase requests, with Visa spend approval, token eligibility guidance, and the advertised browser fill flow (number, expiration MM/YY or MM/YYYY, cvc, exp_month, exp_year); optional actual merchant_category / merchant_category_code
  • add confirm_transaction through --params or --spec-file, validating required fields, enums, integer amounts, ^[A-Z]{3}$ currency, RFC3339 timestamps, and unknown/duplicate properties before any request; reject a currency that differs from the approved purchase or an amount above it; send the exact JSON body without automatic retries
  • allow only an explicitly advertised, parameterless restart_verification in recovery_required; human output, -o json, and execution all hide other operations and stale recovery action URLs
  • give every stop a next step, matching the MCP server:
    • Kernel create transport/5xx: retry once with the identical key and spec
    • authorize / confirm_transaction / restart_verification failures: re-get and invoke once more only if still advertised; authorize 409 needs state inspection, not input changes; 429 waits for Retry-After
    • restart: explicit user approval each time; restart grants no spend consent
    • non-restartable recovery: contact support@kernel.sh privately with project, vault, key, status_reason, and event timestamps; never delete or replace the unresolved item
    • Kernel card updates, merchant decline, or expiry before checkout: with user confirmation, delete only if permitted and create one new card under a new key
    • unknown outcomes: the user checks the merchant, then the confirmed outcome is reported (even after expiry); PENDING / ERROR need explicit merchant evidence
    • wallet reconnect_required / degraded, and bounded network_token_* eligibility re-checks
  • Kernel create/operation errors keep the API message with HTTP(S) URLs scrubbed, and keep *kernel.Error status/code classification without the raw request/response
  • field_unavailable on Kernel fill now says billing details go on the merchant page, instead of "collect missing values"
  • --open help says cardholder links are for a human on their own machine; agents share them privately
  • terminal (decline/expiry/unknown) guidance prints only for ready/declined/expired/consumed cards

compatibility

  • confirm_transaction and restart_verification availability is always gated on available_operations
  • the retained SDK does not yet generate confirm_transaction or restart_verification request types. confirmation uses option.WithRequestBody with validated JSON and option.WithMaxRetries(0); replace the raw body with the typed parameter once the SDK is regenerated

validation

  • make test passed (go vet ./... and go test ./...)
  • make build passed
  • golangci-lint run --new-from-rev=origin/main: 0 issues. full make lint still masks pre-existing warnings; no unrelated lint cleanup included
  • mock HTTP coverage for confirmation validation and approved-purchase matching, re-advertisement-gated retries with identical bodies, identical-key create retry, Retry-After seconds/date, URL scrubbing with SDK error class preserved, recovery JSON/human filtering, status-gated guidance, Kernel fill field set and field_unavailable, and --open help
  • no live payment operations or real API resource mutations

follow-up

  • pre-existing transport-loss guidance for fill (transport loss remains an uncertain outcome) is left unchanged here and should be aligned with the MCP "inspect the page and item, then retry the field write" wording in a separate PR

Note

High Risk
Changes payment credential flows, recovery behavior, and outcome reporting—mistakes could cause duplicate charges, wrong reconciliation, or unsafe handling of card data.

Overview
Adds Kernel-managed vault payments to the CLI: kernel wallets/cards, vaults wallets get, hosted enrollment, token-eligibility guidance, browser fill for ready Kernel cards (no stored billing; origin locked to merchant_url), and blocking card PAN/CVC/expiry in --spec.

Introduces confirm_transaction via --params / --spec-file with strict local validation and a raw JSON POST (no retries) until the SDK exposes the operation type.

Tightens recovery_required: only an advertised, parameterless restart_verification (optional --open) may run; other operations stay blocked with updated errors and human guidance. README and command help document the full Kernel checkout flow (authorize → fill → one-time outcome report).

Reviewed by Cursor Bugbot for commit a18d8a8. Bugbot is set up for automated code reviews on this repo. Configure here.

@hiroTamada hiroTamada changed the title Support Kernel-managed vault wallets and cards in CLI Complete Kernel-managed Visa card checkout in CLI Oct 12, 2026

@rgarcia rgarcia left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

approving — the gating and validation look correct against the openapi spec, and the tests cover the important refusals. most of the findings are about agent steering: where guidance says "don't retry" or "stop" without a recovery path, and where the cli, the mcp server (kernel/kernel-mcp-server#238) and openapi disagree. i'd like the dead ends fixed here or in a fast follow, with #238 matched to the same wording.

dead ends (guidance that leaves the agent with no next step)

  • cmd/vaults_help.go:15 (+ mcp #238 kernelVerificationGuidance) — "invoke it once" strands the agent if the response is lost. the api re-checks restart availability on every call and commits only if the item is unchanged, and restart is no longer listed once it succeeds. suggest: "if the result is unclear, re-read the item and invoke again only if restart_verification is still listed"
  • cmd/vaults_help.go:15, cmd/vaults.go:290, cmd/vaults_output.go:451 — when restart isn't listed: "do not retry, delete, or replace; reconcile with support". delete returns 409 for a kernel card in recovery, so the agent and user have no next step. what should the user do to complete the purchase — a new card item under a new key on the same wallet? if that's safe for this recovery phase, say so with a "one more attempt after user confirmation" limit; if not, say what support does and what state the item ends in
  • cmd/vaults_commands.go:237 (also :101, cmd/vaults_help.go:133, cmd/vaults_output.go:521, README) — "do not report or retry unknown outcomes, including transport loss". the server finishes after a client disconnect, and confirm_transaction is listed only when no report is in flight, none is recorded, and the item isn't in recovery. a provider rejection releases the claim, so the operation is listed again. suggest: "if the result is unclear, run items get; if confirm_transaction is still listed, the report wasn't recorded — send it once more; otherwise stop." mcp #238 has the same dead end
  • same lines — "do not report unknown outcomes" gives no next step. confirm_transaction stays listed while the card is ready or expired and unreported, so: tell the user the outcome is unknown, and report it later once they see it (merchant email, order page, statement). also say when to use PENDING/ERROR and when to call an outcome "unknown"; as written, an agent looking at a "processing…" page can't tell, and the cautious choice is to never report
  • cmd/vaults_output.go:528 — kernel wallet guidance always says "share the card_enrollment url". openapi: reconnect_required → the cardholder uses the new card_enrollment action; degraded → "the wallet must be deleted before adding another card". degraded needs its own guidance, e.g. "with user confirmation, delete this wallet and create a new one for one new enrollment". mcp #238 is also silent here
  • cmd/vaults_output.go:558, cmd/vaults_help.go:20 — "wait for single_use_card.eligible" has no limit and no exit. reasons are network_token_<status> from the provider, and the README says ineligible can mean "pending or unsupported". say which reasons are terminal and give the path: enroll a different card through a new wallet, after user confirmation
  • cmd/vaults_output.go:502 — the kernel card info line prints for every status, including declined, expired and consumed, where "Visa may require spend_approval… submit before expires_at" is misleading. the api allows deleting expired and declined cards, so: expired without submitting → if the user did submit, report first (confirm_transaction is still listed while expired); otherwise, with user confirmation, delete and create one new card item. declined → same, after the user picks a different card or merchant
  • cmd/vaults_commands.go:425, cmd/vaults_help.go:126 — "cannot be updated" has three answers. openapi KernelCardVaultItemSpec: "delete and create a new item instead". this PR: "create a new card item for a new purchase" (dropped the old "delete the item and create a new one"). mcp #238: "inspect the existing item", which leaves no next step. suggest all three say: delete (if the api allows it) and create a new item, after user confirmation

cross-surface consistency

  • cmd/vaults_help.go:15 vs mcp #238 kernelVerificationGuidance — mcp requires explicit user approval before restart_verification; cli doesn't mention approval
  • cmd/vaults_help.go:15 — mirror the openapi wording: restart doesn't grant spend consent; the cardholder must verify and approve again on the new link
  • cmd/vaults_commands.go:241,289, README.md:538,564, wallets get --open — --open on cardholder urls (card_enrollment, spend_approval) opens them on the machine running the cli. mcp #238 says "share privately with the cardholder, never open it for them". when an agent runs the cli, that opens the cardholder's capability url in the agent's own browser. pick one rule for both surfaces
  • cmd/vaults.go:~340 — a confirm_transaction failure goes to util.CleanedUpSdkError with no next step. mcp #238's throwKernelVaultError separates "rejected (4xx): nothing new was authorized; fix inputs before another request" from uncertain failures. the cli should give the same per-error-class guidance
  • cmd/vaults_commands.go:234 — openapi and mcp both say the currency "must match the approved purchase currency"; cli help only says "three uppercase letters"
  • cmd/vaults_commands.go:203 vs mcp #238 — cli lists kernel fill fields as number, expiration (MM/YY or MM/YYYY), cvc, exp_month, exp_year; mcp lists number, expiration ("MM/YY"), cvc. align to what the api supports
  • README.md:550 — the card spec example uses "currency":"usd" and the confirm example uses "USD". use "USD" in both so a copy-pasting agent doesn't think they differ

questions

  • cmd/vaults_policy.go:32-40 vs cmd/vaults_output.go:41 — human output filters recovery operations, but -o json passes available_operations through unchanged. intentional? agents mostly read json

nits

  • cmd/vaults.go:290-293 — "do not retry…" followed by "invoke restart_verification once" reads contradictory; consider a separate message for the listed case
  • cmd/vaults.go:292, cmd/vaults_output.go:452 — len(actions.Operations) > 0 stands in for "restart listed"; an explicit check survives future recovery operations
  • cmd/vaults_confirm_transaction.go:36-44 — the length check plus letter loop could be one ^[A-Z]{3}$ regexp, matching the openapi pattern word for word

follow-up (pre-existing, not this PR)

  • cmd/vaults_commands.go:218 — "transport loss remains an uncertain outcome" for fill has no path. mcp #238 says to inspect the page and item state, then the field write is safe to retry. worth aligning in a separate PR

@hiroTamada
hiroTamada merged commit e7b3c30 into main Oct 13, 2026
8 checks passed
@hiroTamada
hiroTamada deleted the hypeship/kernel-vault-wallet-card branch October 13, 2026 19:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants